package org.lemon.cla.controller;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Min; // 仅用于 resetPasswordByUserId 路径变量，通常用 Long
import jakarta.validation.constraints.NotBlank;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.lemon.cla.dto.request.LoginRequest;
import org.lemon.cla.dto.request.RegisterRequest;
import org.lemon.cla.dto.response.ResponseResult;
import org.lemon.cla.enums.HttpStatusEnum;
import org.lemon.cla.enums.UserRoleEnum;
import org.lemon.cla.pojo.User;
import org.lemon.cla.service.IUserService;
import org.lemon.cla.jwt.JwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional; // 导入 Optional

import org.lemon.cla.exception.BusinessException; // 导入 BusinessException


@RestController
@RequestMapping("/auth")
@Tag(name = "认证管理", description = "提供用户注册、登录及相关认证操作")
@Validated
public class AuthController {

    @Autowired
    private IUserService userService;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private JwtUtil jwtUtil;
    @Operation(summary = "用户注册", description = "创建一个新的用户账户",
            responses = {
                    @ApiResponse(responseCode = "201", description = "注册成功"),
                    @ApiResponse(responseCode = "400", description = "请求参数错误或用户名已存在"),
                    @ApiResponse(responseCode = "500", description = "服务器内部错误")
            })
    @PostMapping("/register")
    public ResponseResult<User> registerUser(@RequestBody @Valid RegisterRequest registerRequest) {
        // 校验用户名是否已存在，如果存在则抛出业务异常
        Optional.ofNullable(userService.getUserByUsername(registerRequest.getUsername()))
                .ifPresent(user -> {
                    throw new BusinessException(HttpStatusEnum.CONFLICT.getCode(), "注册失败：用户名已存在。");
                });

        User newUser = new User();
        newUser.setUsername(registerRequest.getUsername());
        newUser.setPassword(passwordEncoder.encode(registerRequest.getPassword())); // 密码加密
        newUser.setEmail(registerRequest.getEmail());
        newUser.setRealName(registerRequest.getRealName());
        newUser.setPhone(registerRequest.getPhone());
        newUser.setCreateTime(LocalDateTime.now()); // 设置创建时间
        newUser.setLastLogin(LocalDateTime.now()); // 设置初始登录时间
        // 使用 Optional 处理默认值，防止空指针，同时避免 if-else
        newUser.setAvatarUrl("https://2025-1333181667.cos.ap-shanghai.myqcloud.com/2025shixun/338a782c-57aa-456b-afb2-0e58ae48e7f4.webp");
        newUser.setRole(Optional.ofNullable(registerRequest.getRole()).orElse(UserRoleEnum.STUDENT)); // 确保角色有值
        newUser.setIsDeleted(false); // 默认未逻辑删除

        boolean saved = userService.save(newUser); // 如果save返回false但没抛异常，表示操作未成功
        if (!saved) {
            throw new BusinessException(HttpStatusEnum.BAD_REQUEST.getCode(), "注册失败，请稍后重试。"); // 抛出业务异常
        }

        newUser.setPassword(null); // 返回前清空密码
        return ResponseResult.success(HttpStatusEnum.CREATED.getCode(), "注册成功", newUser);
    }

    @Operation(summary = "用户登录", description = "使用用户名和密码进行登录并获取 JWT Token",
            responses = {
                    @ApiResponse(responseCode = "200", description = "登录成功，返回 JWT Token"),
                    @ApiResponse(responseCode = "401", description = "认证失败：用户名或密码错误")
            })
    @PostMapping("/login")
    public ResponseResult<Map<String, String>> loginUser(@RequestBody @Valid LoginRequest loginRequest) {
        // authenticationManager.authenticate() 可能会抛出 BadCredentialsException 等，由GlobalExceptionHandler处理
        Authentication authentication = authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword())
        );

        SecurityContextHolder.getContext().setAuthentication(authentication);

        UserDetails userDetails = (UserDetails) authentication.getPrincipal();

        // 尝试将UserDetails转换为User实体，如果没有成功，则从数据库加载
        User user = Optional.of(userDetails)
                .filter(u -> u instanceof User) // 过滤，确保是User类型
                .map(u -> (User) u) // 映射为User
                .orElseGet(() -> Optional.ofNullable(userService.getUserByUsername(userDetails.getUsername()))
                        .orElseThrow(() -> new BusinessException(HttpStatusEnum.ERROR.getCode(), "登录成功但无法获取完整用户信息。"))); // 抛出业务异常

        // 🚨 更新用户最后登录时间
        user.setLastLogin(LocalDateTime.now());
        boolean updated = userService.updateById(user); // 执行更新操作
        if (!updated) {
            throw new BusinessException(HttpStatusEnum.BAD_REQUEST.getCode(), "登录成功，但更新最后登录时间失败，请稍后重试。");
        }

        String jwt = jwtUtil.generateToken(user);

        Map<String, String> responseData = new HashMap<>();
        responseData.put("token", jwt);
        return ResponseResult.success("登录成功", responseData);
    }

    @Operation(summary = "根据用户ID重置密码", description = "管理员或拥有权限的用户可根据用户ID设置新密码",
            parameters = {
                    @Parameter(name = "userId", description = "要重置密码的用户ID", required = true, example = "1"),
                    @Parameter(name = "newPassword", description = "新密码", required = true, example = "123456")
            },
            requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(
                    description = "新密码字符串", required = true, content = @Content(schema = @Schema(type = "string", description = "新密码", example = "123456"))
            ),
            responses = {
                    @ApiResponse(responseCode = "200", description = "密码重置成功"),
                    @ApiResponse(responseCode = "400", description = "请求参数错误或新密码不符合要求"),
                    @ApiResponse(responseCode = "404", description = "用户未找到")
            })
    @PutMapping("/resetPasswordByUserId/{userId}")
    public ResponseResult<Void> resetPassword(
            @PathVariable Integer userId, // Min注解通常用于RequestParam，PathVariable直接用Integer
            @Parameter @NotBlank(message = "新密码不能为空") String newPassword) {

        // 查找用户，如果不存在则抛出业务异常
        User user = Optional.ofNullable(userService.getById(userId))
                .orElseThrow(() -> new BusinessException(HttpStatusEnum.NOT_FOUND.getCode(), "重置密码失败：用户不存在。"));

        user.setPassword(passwordEncoder.encode(newPassword)); // 加密新密码
        boolean updated = userService.updateById(user); // 如果更新失败，抛出业务异常

        if (!updated) {
            throw new BusinessException(HttpStatusEnum.ERROR.getCode(), "密码重置失败，请稍后重试。");
        }
        return ResponseResult.success("密码重置成功！");
    }

    @Operation(summary = "根据用户名重置密码", description = "管理员或拥有权限的用户可根据用户ID设置新密码",
            parameters = {
                    @Parameter(name = "userName", description = "要重置密码的用户名(userName)", required = true, example = "testName"),
                    @Parameter(name = "newPassword", description = "新密码", required = true, example = "123456")
            },
            requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(
                    description = "新密码字符串", required = true, content = @Content(schema = @Schema(type = "string", description = "新密码", example = "123456"))
            ),
            responses = {
                    @ApiResponse(responseCode = "200", description = "密码重置成功"),
                    @ApiResponse(responseCode = "400", description = "请求参数错误或新密码不符合要求"),
                    @ApiResponse(responseCode = "404", description = "用户未找到")
            })
    @PutMapping("/resetPasswordByUserName/{userName}")
    public ResponseResult<Void> resetPassword(
            @PathVariable String userName,
            @Parameter @NotBlank(message = "新密码不能为空") String newPassword) {

        // 查找用户，如果不存在则抛出业务异常
        User user = Optional.ofNullable(userService.getUserByUsername(userName))
                .orElseThrow(() -> new BusinessException(HttpStatusEnum.NOT_FOUND.getCode(), "重置密码失败：用户不存在。"));

        user.setPassword(passwordEncoder.encode(newPassword)); // 加密新密码
        boolean updated = userService.updateById(user); // 如果更新失败，抛出业务异常

        if (!updated) {
            throw new BusinessException(HttpStatusEnum.BAD_REQUEST.getCode(), "密码重置失败，请稍后重试。");
        }
        return ResponseResult.success("密码重置成功！");
    }

    @Operation(summary = "用户登出", description = "客户端删除本地 JWT Token 即可，服务器端通常无需操作。",
            responses = {
                    @ApiResponse(responseCode = "200", description = "登出操作提示成功")
            })
    @PostMapping("/logout")
    public ResponseResult<Void> logoutUser() {
        return ResponseResult.success("您已成功登出。");
    }

    @Operation(summary = "解析JWT Token内容", description = "此接口需要Token认证。传入另一个JWT Token字符串，解析其内容。",
            parameters = {
                    @Parameter(name = "tokenToParse", description = "要解析的JWT Token字符串 (不带Bearer前缀)", required = true, example = "eyJ...")
            },
            requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(
                    description = "纯JWT Token字符串", required = true, content = @Content(schema = @Schema(type = "string", example = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"))
            ),
            responses = {
                    @ApiResponse(responseCode = "200", description = "成功解析Token"),
                    @ApiResponse(responseCode = "401", description = "认证失败：请求头中缺少有效Token或Token过期"),
                    @ApiResponse(responseCode = "400", description = "请求体中Token格式不正确"),
                    @ApiResponse(responseCode = "500", description = "服务器内部错误")
            })
    @PostMapping("/parseAnyToken")
    public ResponseResult<Map<String, Object>> parseAnyToken(
            @io.swagger.v3.oas.annotations.parameters.RequestBody(
                    description = "纯JWT Token字符串", required = true, content = @Content(schema = @Schema(type = "string", example = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"))
            ) @org.springframework.web.bind.annotation.RequestBody @NotBlank(message = "Token字符串不能为空") String tokenToParse) {

        String cleanToken = Optional.ofNullable(tokenToParse)
                .filter(s -> !s.isEmpty())
                .map(s -> s.startsWith("Bearer ") ? s.substring(7) : s)
                .orElseThrow(() -> new BusinessException(HttpStatusEnum.BAD_REQUEST.getCode(), "Token字符串不能为空或格式不正确。"));

        // jwtUtil.extractAllClaims 可能会抛出 JWTVerificationException，由GlobalExceptionHandler处理
        Map<String, Object> claims = jwtUtil.extractAllClaims(cleanToken);

        return ResponseResult.success(HttpStatusEnum.SUCCESS.getCode(), "Token 解析成功", claims);
    }
}
